import mongoose, { Schema, Document, Model } from 'mongoose';
import { v4 as uuidv4 } from 'uuid';
import crypto from 'crypto';

/**
 * 系统状态枚举
 */
export enum SystemStatus {
  ACTIVE = 'active',     // 激活状态
  INACTIVE = 'inactive', // 非激活状态
  SUSPENDED = 'suspended', // 暂停状态
  MAINTENANCE = 'maintenance' // 维护状态
}

/**
 * 系统类型枚举
 */
export enum SystemType {
  WEB = 'web',           // Web应用
  MOBILE = 'mobile',     // 移动应用
  API = 'api',           // API服务
  MICROSERVICE = 'microservice', // 微服务
  DESKTOP = 'desktop'    // 桌面应用
}

/**
 * 系统接口定义
 */
export interface ISystem {
  systemCode: string;        // 系统代码（唯一标识）
  systemName: string;        // 系统名称
  systemType: SystemType;    // 系统类型
  description?: string;      // 系统描述
  version: string;           // 系统版本
  status: SystemStatus;      // 系统状态
  secretKey: string;         // 系统密钥（用于API认证）
  callbackUrl?: string;      // 回调URL
  allowedOrigins: string[];  // 允许的来源域名
  metadata?: Record<string, any>; // 元数据
  registeredAt: Date;        // 注册时间
  lastActiveAt?: Date;       // 最后活跃时间
  createdBy: mongoose.Types.ObjectId; // 创建者ID
  updatedBy?: mongoose.Types.ObjectId; // 更新者ID
  createdAt: Date;           // 创建时间
  updatedAt: Date;           // 更新时间
}

/**
 * 系统文档接口（包含实例方法）
 */
export interface ISystemDocument extends ISystem, Document {
  /**
   * 自定义JSON序列化
   * @returns 序列化后的对象
   */
  toJSON(): any;

  /**
   * 检查系统是否处于活跃状态
   * @returns 是否活跃
   */
  isActive(): boolean;

  /**
   * 检查系统是否可以访问
   * @returns 是否可访问
   */
  canAccess(): boolean;

  /**
   * 验证来源域名是否被允许
   * @param origin 来源域名
   * @returns 是否被允许
   */
  isOriginAllowed(origin: string): boolean;

  /**
   * 更新最后活跃时间
   * @returns Promise<ISystemDocument>
   */
  updateLastActive(): Promise<ISystemDocument>;

  /**
   * 重新生成系统密钥
   * @returns Promise<string> 新的密钥
   */
  regenerateSecretKey(): Promise<string>;

  /**
   * 获取系统详细信息
   * @returns 系统详细信息
   */
  getDetailInfo(): any;

  /**
   * 验证系统密钥
   * @param secretKey 待验证的密钥
   * @returns 是否验证通过
   */
  verifySecretKey(secretKey: string): boolean;
}

/**
 * 系统模型接口（包含静态方法）
 */
export interface ISystemModel extends Model<ISystemDocument> {
  /**
   * 根据系统代码查找系统
   * @param systemCode 系统代码
   * @returns Promise<ISystemDocument | null>
   */
  findBySystemCode(systemCode: string): Promise<ISystemDocument | null>;

  /**
   * 根据系统类型查找系统列表
   * @param systemType 系统类型
   * @param status 系统状态（可选）
   * @returns Promise<ISystemDocument[]>
   */
  findByType(systemType: SystemType, status?: SystemStatus): Promise<ISystemDocument[]>;

  /**
   * 根据状态查找系统列表
   * @param status 系统状态
   * @returns Promise<ISystemDocument[]>
   */
  findByStatus(status: SystemStatus): Promise<ISystemDocument[]>;

  /**
   * 批量注册系统
   * @param systems 系统信息数组
   * @param createdBy 创建者ID
   * @returns Promise<ISystemDocument[]>
   */
  batchRegister(systems: Partial<ISystem>[], createdBy: mongoose.Types.ObjectId): Promise<ISystemDocument[]>;

  /**
   * 更新系统状态
   * @param systemId 系统ID
   * @param status 新状态
   * @param updatedBy 更新者ID
   * @returns Promise<ISystemDocument | null>
   */
  updateStatus(systemId: mongoose.Types.ObjectId, status: SystemStatus, updatedBy: mongoose.Types.ObjectId): Promise<ISystemDocument | null>;

  /**
   * 获取活跃系统统计
   * @param timeRange 时间范围（小时）
   * @returns Promise<number>
   */
  getActiveSystemCount(timeRange?: number): Promise<number>;

  /**
   * 获取系统状态统计
   * @returns Promise<Record<SystemStatus, number>>
   */
  getStatusStatistics(): Promise<Record<SystemStatus, number>>;

  /**
   * 清理非活跃系统
   * @param inactiveDays 非活跃天数阈值
   * @returns Promise<number> 清理的系统数量
   */
  cleanupInactiveSystems(inactiveDays: number): Promise<number>;

  /**
   * 验证系统访问权限
   * @param systemCode 系统代码
   * @param secretKey 系统密钥
   * @param origin 来源域名（可选）
   * @returns Promise<ISystemDocument | null>
   */
  verifySystemAccess(systemCode: string, secretKey: string, origin?: string): Promise<ISystemDocument | null>;

  /**
   * 搜索系统
   * @param keyword 关键词
   * @param filters 过滤条件
   * @returns Promise<ISystemDocument[]>
   */
  searchSystems(keyword: string, filters?: { type?: SystemType; status?: SystemStatus }): Promise<ISystemDocument[]>;
}

/**
 * 系统Schema定义
 */
const SystemSchema = new Schema<ISystemDocument>({
  systemCode: {
    type: String,
    required: [true, '系统代码不能为空'],
    unique: true,
    trim: true,
    maxlength: [50, '系统代码长度不能超过50个字符'],
    match: [/^[a-zA-Z0-9_-]+$/, '系统代码只能包含字母、数字、下划线和连字符']
  },
  systemName: {
    type: String,
    required: [true, '系统名称不能为空'],
    trim: true,
    maxlength: [100, '系统名称长度不能超过100个字符']
  },
  systemType: {
    type: String,
    enum: Object.values(SystemType),
    required: [true, '系统类型不能为空']
  },
  description: {
    type: String,
    trim: true,
    maxlength: [500, '系统描述长度不能超过500个字符']
  },
  version: {
    type: String,
    required: [true, '系统版本不能为空'],
    trim: true,
    maxlength: [20, '版本号长度不能超过20个字符'],
    match: [/^\d+\.\d+\.\d+$/, '版本号格式应为 x.y.z']
  },
  status: {
    type: String,
    enum: Object.values(SystemStatus),
    default: SystemStatus.ACTIVE
  },
  secretKey: {
    type: String,
    default: function() {
      return crypto.randomBytes(32).toString('hex');
    },
    select: false // 默认不返回密钥
  },
  callbackUrl: {
    type: String,
    trim: true,
    validate: {
      validator: function(v: string) {
        if (!v) return true; // 可选字段
        try {
          new URL(v);
          return true;
        } catch {
          return false;
        }
      },
      message: '回调URL格式不正确'
    }
  },
  allowedOrigins: {
    type: [String],
    default: [],
    validate: {
      validator: function(origins: string[]) {
        return origins.every(origin => {
          try {
            new URL(origin);
            return true;
          } catch {
            return origin === '*'; // 允许通配符
          }
        });
      },
      message: '允许的来源域名格式不正确'
    }
  },
  metadata: {
    type: Schema.Types.Mixed,
    default: {}
  },
  registeredAt: {
    type: Date,
    default: Date.now
  },
  lastActiveAt: {
    type: Date
  },
  createdBy: {
    type: Schema.Types.ObjectId,
    ref: 'User',
    required: [true, '创建者不能为空']
  },
  updatedBy: {
    type: Schema.Types.ObjectId,
    ref: 'User'
  }
}, {
  timestamps: true,
  versionKey: false
});

// 创建索引
SystemSchema.index({ systemCode: 1 }, { unique: true });
SystemSchema.index({ systemType: 1, status: 1 });
SystemSchema.index({ status: 1 });
SystemSchema.index({ lastActiveAt: 1 });
SystemSchema.index({ createdAt: 1 });
SystemSchema.index({ systemName: 'text', description: 'text' }); // 文本搜索索引

// Pre-save中间件：生成密钥
SystemSchema.pre<ISystemDocument>('save', function(next) {
  if (this.isNew && !this.secretKey) {
    this.secretKey = crypto.randomBytes(32).toString('hex');
  }
  
  if (this.isNew) {
    this.registeredAt = new Date();
  }
  
  next();
});

// 实例方法实现
SystemSchema.methods.toJSON = function() {
  const obj = this.toObject();
  delete obj.secretKey; // 不返回密钥
  return obj;
};

SystemSchema.methods.isActive = function(): boolean {
  return this.status === SystemStatus.ACTIVE;
};

SystemSchema.methods.canAccess = function(): boolean {
  return this.status === SystemStatus.ACTIVE || this.status === SystemStatus.MAINTENANCE;
};

SystemSchema.methods.isOriginAllowed = function(origin: string): boolean {
  if (this.allowedOrigins.includes('*')) {
    return true;
  }
  return this.allowedOrigins.includes(origin);
};

SystemSchema.methods.updateLastActive = async function(): Promise<ISystemDocument> {
  this.lastActiveAt = new Date();
  return await this.save();
};

SystemSchema.methods.regenerateSecretKey = async function(): Promise<string> {
  this.secretKey = crypto.randomBytes(32).toString('hex');
  await this.save();
  return this.secretKey;
};

SystemSchema.methods.getDetailInfo = function() {
  const obj = this.toObject();
  return {
    ...obj,
    isActive: this.isActive(),
    canAccess: this.canAccess(),
    daysSinceLastActive: this.lastActiveAt ? 
      Math.floor((Date.now() - this.lastActiveAt.getTime()) / (1000 * 60 * 60 * 24)) : null
  };
};

SystemSchema.methods.verifySecretKey = function(secretKey: string): boolean {
  return this.secretKey === secretKey;
};

// 静态方法实现
SystemSchema.statics.findBySystemCode = async function(systemCode: string): Promise<ISystemDocument | null> {
  return this.findOne({ systemCode }).select('+secretKey');
};

SystemSchema.statics.findByType = async function(systemType: SystemType, status?: SystemStatus): Promise<ISystemDocument[]> {
  const query: any = { systemType };
  if (status) {
    query.status = status;
  }
  return await this.find(query).populate('createdBy', 'username email').populate('updatedBy', 'username email');
};

SystemSchema.statics.findByStatus = async function(status: SystemStatus): Promise<ISystemDocument[]> {
  return await this.find({ status }).populate('createdBy', 'username email');
};

SystemSchema.statics.batchRegister = async function(systems: Partial<ISystem>[], createdBy: mongoose.Types.ObjectId): Promise<ISystemDocument[]> {
  const systemsToCreate = systems.map(system => ({
    ...system,
    createdBy,
    status: system.status || SystemStatus.ACTIVE,
    secretKey: system.secretKey || crypto.randomBytes(32).toString('hex'),
    registeredAt: new Date()
  }));
  
  const result = await this.insertMany(systemsToCreate);
  return result as ISystemDocument[];
};

SystemSchema.statics.updateStatus = async function(systemId: mongoose.Types.ObjectId, status: SystemStatus, updatedBy: mongoose.Types.ObjectId): Promise<ISystemDocument | null> {
  return this.findByIdAndUpdate(
    systemId,
    { status, updatedBy },
    { new: true }
  );
};

SystemSchema.statics.getActiveSystemCount = async function(timeRange: number = 24): Promise<number> {
  const cutoffTime = new Date(Date.now() - timeRange * 60 * 60 * 1000);
  return await this.countDocuments({
    status: SystemStatus.ACTIVE,
    lastActiveAt: { $gte: cutoffTime }
  });
};

SystemSchema.statics.getStatusStatistics = async function(): Promise<Record<SystemStatus, number>> {
  const pipeline = [
    {
      $group: {
        _id: '$status',
        count: { $sum: 1 }
      }
    }
  ];
  
  const results = await this.aggregate(pipeline);
  const statistics: Record<SystemStatus, number> = {
    [SystemStatus.ACTIVE]: 0,
    [SystemStatus.INACTIVE]: 0,
    [SystemStatus.SUSPENDED]: 0,
    [SystemStatus.MAINTENANCE]: 0
  };
  
  results.forEach(result => {
    statistics[result._id as SystemStatus] = result.count;
  });
  
  return statistics;
};

SystemSchema.statics.cleanupInactiveSystems = async function(inactiveDays: number): Promise<number> {
  const cutoffTime = new Date(Date.now() - inactiveDays * 24 * 60 * 60 * 1000);
  const result = await this.deleteMany({
    status: SystemStatus.INACTIVE,
    $or: [
      { lastActiveAt: { $lt: cutoffTime } },
      { lastActiveAt: { $exists: false }, createdAt: { $lt: cutoffTime } }
    ]
  });
  
  return result.deletedCount || 0;
};

SystemSchema.statics.verifySystemAccess = async function(systemCode: string, secretKey: string, origin?: string): Promise<ISystemDocument | null> {
  const system = await this.findOne({ systemCode }).select('+secretKey');
  
  if (!system || !system.canAccess() || !system.verifySecretKey(secretKey)) {
    return null;
  }
  
  if (origin && !system.isOriginAllowed(origin)) {
    return null;
  }
  
  // 更新最后活跃时间
  await system.updateLastActive();
  
  // 重新查询以获取完整的system对象（不包含secretKey）
  return await this.findOne({ systemCode });
};

SystemSchema.statics.searchSystems = async function(keyword: string, filters?: { type?: SystemType; status?: SystemStatus }): Promise<ISystemDocument[]> {
  const query: any = {
    $or: [
      { systemName: { $regex: keyword, $options: 'i' } },
      { systemCode: { $regex: keyword, $options: 'i' } },
      { description: { $regex: keyword, $options: 'i' } }
    ]
  };
  
  if (filters?.type) {
    query.systemType = filters.type;
  }
  
  if (filters?.status) {
    query.status = filters.status;
  }
  
  return await this.find(query)
    .populate('createdBy', 'username email')
    .populate('updatedBy', 'username email')
    .sort({ createdAt: -1 });
};

// 创建并导出模型
const System = mongoose.model<ISystemDocument, ISystemModel>('System', SystemSchema);

export default System;
export { System };